#pragma once
#include <string>
#include <vector>
#include <fstream>
#include <torch/torch.h>
#include "DCBEstimator.h"
#include <map>

/**
 * @brief 时间点结构，用于标识VTEC地图的时间
 */
struct TimePoint {
    int year;
    int month;
    int day;
    int hour;
    int minute;
    int second;
    
    // 构造函数
    TimePoint(int y = 0, int m = 0, int d = 0, int h = 0, int min = 0, int s = 0)
        : year(y), month(m), day(d), hour(h), minute(min), second(s) {}
    
    // 比较运算符，用于map排序
    bool operator<(const TimePoint& other) const {
        if (year != other.year) return year < other.year;
        if (month != other.month) return month < other.month;
        if (day != other.day) return day < other.day;
        if (hour != other.hour) return hour < other.hour;
        if (minute != other.minute) return minute < other.minute;
        return second < other.second;
    }
};

/**
 * @class IONEXWriter
 * @brief 用于生成IONEX格式的电离层图和DCB估计值输出文件
 */
class IONEXWriter {
public:
    IONEXWriter();
    ~IONEXWriter();

    /**
     * @brief 设置VTEC网格数据
     * @param vtecGrid VTEC网格数据张量
     */
    void setVTECGrid(const torch::Tensor& vtecGrid);
    
    /**
     * @brief 设置特定时间点的VTEC网格数据
     * @param time 时间点
     * @param vtecGrid VTEC网格数据张量
     */
    void setVTECGridForTime(const TimePoint& time, const torch::Tensor& vtecGrid);
    
    /**
     * @brief 设置卫星DCB估计结果
     * @param satDCBs 卫星DCB估计结果向量
     */
    void setSatelliteDCBs(const std::vector<DCBResult>& satDCBs);
    
    /**
     * @brief 设置特定时间点的卫星DCB估计结果
     * @param time 时间点
     * @param satDCBs 卫星DCB估计结果向量
     */
    void setSatelliteDCBsForTime(const TimePoint& time, const std::vector<DCBResult>& satDCBs);
    
    /**
     * @brief 设置接收机DCB估计结果
     * @param recDCBs 接收机DCB估计结果向量
     */
    void setReceiverDCBs(const std::vector<DCBResult>& recDCBs);
    
    /**
     * @brief 设置特定时间点的接收机DCB估计结果
     * @param time 时间点
     * @param recDCBs 接收机DCB估计结果向量
     */
    void setReceiverDCBsForTime(const TimePoint& time, const std::vector<DCBResult>& recDCBs);
    
    /**
     * @brief 设置电离层等效高度
     * @param height 高度(km)
     */
    void setIonosphereHeight(double height) { ionoHeight_ = height; }
    
    /**
     * @brief 设置电离层地图时间
     * @param year 年
     * @param month 月
     * @param day 日
     * @param hour 时
     * @param minute 分
     * @param second 秒
     */
    void setMapTime(int year, int month, int day, int hour, int minute, int second);
    
    /**
     * @brief 写入IONEX文件
     * @param filename 输出文件名
     * @return 是否成功写入
     */
    bool writeIONEXFile(const std::string& filename);
    
    /**
     * @brief 写入DCB文件
     * @param filename 输出文件名
     * @return 是否成功写入
     */
    bool writeDCBFile(const std::string& filename);

    /**
     * @brief 创建IONEX文件(用于多时间点流式写入)
     * @param filename 输出文件名
     * @return 是否成功创建
     */
    bool createIONEXFile(const std::string& filename);
    
    /**
     * @brief 添加一个时间点的数据(包括球谐系数、卫星DCB和接收机DCB)
     * @param time 时间点
     * @param shCoeffs 球谐系数
     * @param satDCBs 卫星DCB (字符串到double的映射)
     * @param recDCBs 接收机DCB (字符串到double的映射)
     * @return 是否成功添加
     */
    bool addEpoch(const TimePoint& time, 
                 const std::vector<double>& shCoeffs,
                 const std::map<std::string, double>& satDCBs,
                 const std::map<std::string, double>& recDCBs);
    
    /**
     * @brief 完成IONEX文件写入
     * @return 是否成功
     */
    bool finalizeIONEXFile();

private:
    torch::Tensor vtecGrid_;             // VTEC网格数据 (用于向后兼容)
    std::map<TimePoint, torch::Tensor> timeVtecGrids_; // 各时间点的VTEC网格数据
    
    std::vector<DCBResult> satelliteDCBs_; // 卫星DCB结果 (用于向后兼容)
    std::vector<DCBResult> receiverDCBs_;  // 接收机DCB结果 (用于向后兼容)
    
    std::map<TimePoint, std::vector<DCBResult>> timeSatelliteDCBs_; // 各时间点的卫星DCB结果
    std::map<TimePoint, std::vector<DCBResult>> timeReceiverDCBs_;  // 各时间点的接收机DCB结果
    
    double ionoHeight_ = 350.0;          // 电离层等效高度(km)
    
    // 地图时间 (用于向后兼容)
    int year_ = 0;
    int month_ = 0;
    int day_ = 0;
    int hour_ = 0;
    int minute_ = 0;
    int second_ = 0;
    
    // 存储各时间点的球谐系数
    std::map<TimePoint, std::vector<double>> timeShCoeffs_;
    
    // 存储各时间点的原始DCB结果
    std::map<TimePoint, std::map<std::string, double>> timeSatDCBMap_;
    std::map<TimePoint, std::map<std::string, double>> timeRecDCBMap_;
    
    // 文件流
    std::ofstream* outputFile_ = nullptr;
    std::string outputFilename_;
    
    /**
     * @brief 写入IONEX头部
     * @param file 文件流
     */
    void writeHeader(std::ofstream& file);
    
    /**
     * @brief 写入TEC地图
     * @param file 文件流
     * @param time 时间点
     * @param mapIndex 地图索引
     * @param vtecGrid VTEC网格数据
     */
    void writeTECMap(std::ofstream& file, const TimePoint& time, int mapIndex, const torch::Tensor& vtecGrid);
    
    /**
     * @brief 写入DCB数据部分
     * @param file 文件流
     */
    void writeDCBValues(std::ofstream& file);

    /**
     * @brief 从球谐系数生成VTEC网格
     * @param shCoeffs 球谐系数
     * @param degree 球谐阶数
     * @param latRes 纬度分辨率
     * @param lonRes 经度分辨率
     * @return VTEC网格
     */
    torch::Tensor generateVTECGridFromCoefficients(
        const std::vector<double>& shCoeffs, 
        int degree, 
        double latRes = 5.0, 
        double lonRes = 5.0);
}; 